package cn.dyn.funchat.channel;

import cn.dyn.funchat.handler.NettyExceptionHandler;
import cn.dyn.funchat.netty.server.handler.HeartbeatHandler;
import cn.dyn.funchat.netty.server.handler.WebsocketHandler;
import cn.dyn.funchat.netty.server.prop.NettyProp;
import cn.dyn.funchat.utils.TraceIdUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;

import javax.net.ssl.KeyManagerFactory;
import java.io.InputStream;
import java.security.KeyStore;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

@Slf4j
public class ChannelInit extends ChannelInitializer<Channel> {
    /**
     * netty的yml配置
     */
    private final NettyProp nettyProp;

    public ChannelInit(NettyProp nettyProp) {
        this.nettyProp = Optional.ofNullable(nettyProp).orElse(new NettyProp());
    }

    @Override
    protected void initChannel(Channel channel) throws Exception {
        TraceIdUtil.putTraceId();
        ChannelPipeline channelPipeline = channel.pipeline();
        NettyProp.Ssl ssl = Optional.ofNullable(nettyProp.getSsl()).orElse(new NettyProp.Ssl());
        if (ssl.getEnable()){
            // 添加 SSL 处理器
            SslContext sslCtx = getSslContext();
            if (sslCtx != null) {
                channelPipeline.addLast(sslCtx.newHandler(channel.alloc()));
            }
        }
        // 设置http编码协议 对http协议的支持，使用http的编码器，解码器
        channelPipeline.addLast(new HttpServerCodec());
        // 聚合http请求，保证http请求完整性
        channelPipeline.addLast(new HttpObjectAggregator(10 * 1024 * 1024));
        // 心跳检测
        // long readerIdleTime, long writerIdleTime, long allIdleTime, TimeUnit unit
        // readerIdleTime 读超时（一定时间客户端没有发消息给服务端）0表示不检测
        // writerIdleTime 写超时（一定时间没有给客户端发送消息）0表示不检测
        // allIdleTime 所有类型超时时间，0表示不检测
        // unit 时间单位
        channelPipeline.addLast(new IdleStateHandler(60, 0, 0, TimeUnit.SECONDS));
        // 心跳检测处理器
        channelPipeline.addLast(new HeartbeatHandler());
        // 将http协议升级为websocket协议
        channelPipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
        // 添加自定义的websocket处理器
        channelPipeline.addLast(new WebsocketHandler());
        // 添加自定义异常处理器：
        channelPipeline.addLast(new NettyExceptionHandler());
    }

    private SslContext getSslContext() {
        try {
            // 1. 用 Hutool 加载 keystore.jks
            InputStream stream = ResourceUtil.getStream("keystore.jks");
            KeyStore keyStore = KeyStore.getInstance("JKS");
            keyStore.load(stream, "vZ5@pU1*kS5&yI2%iF1".toCharArray());
            stream.close();
            // 2. 创建 KeyManagerFactory
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(keyStore, "vZ5@pU1*kS5&yI2%iF1".toCharArray());

            // 3. 构建 Netty 的 SslContext
            SslContext sslCtx = SslContextBuilder.forServer(kmf).build();
            return sslCtx;
        } catch (Exception e) {
            log.error("加载ssl配置失败：{}", e.getMessage());
            return null;
        }
    }
}
